/*
微信公众平台相关功能接口
@Time : 2019/2/28 0028 14:41
@Author : visons
*/
package platform

import (
	"crypto/sha1"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/visons/gopkg/logger"
	"github.com/levigross/grequests"
	"github.com/tobyzxj/uuid"
	"strings"
	"time"
)

//微信网页授权登录,获取用户信息
func GetWeiXinUserInfo(code, appId, secret string) (*WeiXinUserInfo, error) {
	//获取access_token的请求参数
	var params = map[string]string{
		"appid":      appId,
		"secret":     secret,
		"code":       code,
		"grant_type": "authorization_code",
	}
	ro := &grequests.RequestOptions{
		Params:         params,
		DialTimeout:    time.Second * 5,
		RequestTimeout: time.Second * 5,
	}
	res, err := grequests.Get("https://api.weixin.qq.com/sns/oauth2/access_token", ro)
	logger.Info("res:%v", res)
	if err != nil {
		logger.Error("get weixin access_token failed: %v", err)
		return nil, err
	}

	code2accesstoken := &Code2AccessToken{}
	err = json.Unmarshal(res.Bytes(), code2accesstoken)
	if err != nil {
		logger.Error("access_token data to json: %v", err)
		return nil, err
	}

	if code2accesstoken.Errcode != 0 {
		err = errors.New(fmt.Sprintf("get weixin accessToekn result: {errorcode: %d,errormsg:%s} ",
			code2accesstoken.Errcode, code2accesstoken.ErrMsg))
		logger.Error(err)
		return nil, err
	}

	//获取用户信息
	params = map[string]string{
		"access_token": code2accesstoken.AccessToken,
		"openid":       code2accesstoken.Openid,
		"lang":         "zh_CN",
	}
	ro = &grequests.RequestOptions{
		Params:         params,
		DialTimeout:    time.Second * 5,
		RequestTimeout: time.Second * 5,
	}

	res, err = grequests.Get("https://api.weixin.qq.com/sns/userinfo", ro)
	if err != nil {
		logger.Error("get weixin userinfo %v", err)
		return nil, err
	}

	userInfo := &WeiXinUserInfo{}
	err = json.Unmarshal(res.Bytes(), userInfo)
	if err != nil {
		logger.Error("unmarshal userInfo byte data to json %v", err)
		return nil, err
	}

	if userInfo.Errcode != 0 {
		err = errors.New(fmt.Sprintf("get userinfo result: {errorcode: %d,errormsg:%s}",
			code2accesstoken.Errcode, code2accesstoken.ErrMsg))
		logger.Error(err)
		return nil, err
	}
	return userInfo, nil
}

//获取用户签名信息
func GetAccessToken(appId, secret string) (*AccessToken, error) {
	var params = map[string]string{
		"appid":      appId,
		"secret":     secret,
		"grant_type": "client_credential",
	}
	ro := &grequests.RequestOptions{
		Params:         params,
		DialTimeout:    time.Second * 5,
		RequestTimeout: time.Second * 5,
	}
	res, err := grequests.Get("https://api.weixin.qq.com/cgi-bin/token", ro)
	if err != nil {
		logger.Error("get access_token fail:%v", err)
		return nil, err
	}

	accessToken := &AccessToken{}
	err = json.Unmarshal(res.Bytes(), accessToken)
	if err != nil {
		logger.Error("Unmarshal token date fail:%v", err)
		return nil, err
	}

	if accessToken.Errcode != 0 {
		err = errors.New(fmt.Sprintf("get accessToekn result: {errorcode: %d,errormsg:%s}",
			accessToken.Errcode, accessToken.ErrMsg))
		logger.Error(err)
		return nil, err
	}
	return accessToken, nil
}

//获取调用微信JS接口的临时票据
func GetJsapiTicket(accessToken string) (*JsapiTicket, error) {
	var params = map[string]string{
		"access_token": accessToken,
		"type":         "jsapi",
	}
	ro := &grequests.RequestOptions{
		Params:         params,
		DialTimeout:    time.Second * 5,
		RequestTimeout: time.Second * 5,
	}
	res, err := grequests.Get("https://api.weixin.qq.com/cgi-bin/ticket/getticket", ro)
	if err != nil {
		logger.Error("request get jsapi_ticket fail：%v", err)
		return nil, err
	}

	ticket := &JsapiTicket{}
	err = json.Unmarshal(res.Bytes(), ticket)
	if err != nil {
		logger.Error("Unmarshal response data fail：%v", err)
		return nil, err
	}

	if ticket.Errcode != 0 {
		err = errors.New(fmt.Sprintf("get jsapi_ticket result: {errorcode: %d,errormsg:%s}",
			ticket.Errcode, ticket.ErrMsg))
		logger.Error(err)
		return nil, err
	}
	return ticket, nil
}

/**
获取签名信息
@param ticket 生成签名的jsapi_ticket
@param url  JS接口页面的完整URL
*/
func GetSignatureInfo(ticket, url string) *SignatureInfo {
	sign := &SignatureInfo{}
	noncestr := GetRandomString()
	timestamp := time.Now().Unix()

	sigStr := fmt.Sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s", ticket, noncestr, timestamp, url)
	logger.Info("参与签名字符串：%s", sigStr)
	signature := GetSHA1Str(sigStr)

	sign.Signature = signature
	sign.Timestamp = timestamp
	sign.Noncestr = noncestr
	return sign
}

//获取随机字符串
func GetRandomString() string {
	return strings.Replace(uuid.New(), "-", "", -1)
}

//sha1签名
func GetSHA1Str(str string) string {
	h := sha1.New()
	h.Write([]byte(str))
	bs := h.Sum(nil)
	sha1Str := fmt.Sprintf("%x", bs)
	return sha1Str
}
